package com.marmot.cloud.framework.orm.jpa.comment.bean;

import cn.hutool.core.util.ReflectUtil;
import com.marmot.cloud.framework.orm.jpa.comment.annotation.Comment;
import org.hibernate.boot.Metadata;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;

/**
 * 自定义的 Hibernate 整合器，用于处理实体类和属性上的注释信息，并将其映射到数据库表和列的注释中。
 */
public class CommentIntegrator implements Integrator {
    /** CommentIntegrator 的单例实例 */
    public static final CommentIntegrator INSTANCE = new CommentIntegrator();

    /**
     * 构造方法
     */
    public CommentIntegrator() {
        super();
    }

    /**
     * 将注释信息整合到 Hibernate 元数据中
     *
     * @param metadata           Hibernate 元数据
     * @param sessionFactory     Hibernate 会话工厂
     * @param serviceRegistry    Hibernate 服务注册中心
     */
    @Override
    public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
        processComment(metadata);
    }

    /**
     * 在取消整合时不进行任何操作
     *
     * @param sessionFactoryImplementor   Hibernate 会话工厂实现
     * @param sessionFactoryServiceRegistry   Hibernate 服务注册中心
     */
    @Override
    public void disintegrate(SessionFactoryImplementor sessionFactoryImplementor, SessionFactoryServiceRegistry sessionFactoryServiceRegistry) {
    }

    /**
     * 处理实体类和属性上的注释信息，并将其映射到数据库表和列的注释中
     *
     * @param metadata   Hibernate 元数据
     */
    protected void processComment(Metadata metadata) {
        for (PersistentClass persistentClass : metadata.getEntityBindings()) {
            Class<?> clz = persistentClass.getMappedClass();
            // 处理实体类上的注释信息，映射到数据库表的注释中
            if (clz.isAnnotationPresent(Comment.class)) {
                Comment tableComment = clz.getAnnotation(Comment.class);
                persistentClass.getTable().setComment(tableComment.value());
            }
            // 处理主键属性的注释信息
            Property identifierProperty = persistentClass.getIdentifierProperty();
            if (identifierProperty != null) {
                propertyComment(persistentClass, identifierProperty.getName());
            } else {
                org.hibernate.mapping.Component component = persistentClass.getIdentifierMapper();
                if (component != null) {
                    Iterator<Property> iterator = component.getPropertyIterator();
                    while (iterator.hasNext()) {
                        propertyComment(persistentClass, iterator.next().getName());
                    }
                }
            }
            // 处理普通属性的注释信息
            Iterator<Property> iterator = persistentClass.getProperties().iterator();
            while (iterator.hasNext()) {
                propertyComment(persistentClass, iterator.next().getName());
            }
        }
    }

    /**
     * 将属性上的注释信息映射到数据库列的注释中
     *
     * @param persistentClass   持久化类
     * @param columnName        列名
     */
    private void propertyComment(PersistentClass persistentClass, String columnName) {
        try {
            String comment = getPropertyComment(persistentClass, columnName);
            String sqlColumnName = persistentClass.getProperty(columnName).getValue().getColumns().iterator().next().getText();
            Iterator<Column> columnIterator = persistentClass.getTable().getColumns().iterator();
            while (columnIterator.hasNext()) {
                Column column = columnIterator.next();
                if (sqlColumnName.equalsIgnoreCase(column.getName())) {
                    column.setComment(comment);
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取属性上的注释信息
     *
     * @param persistentClass   持久化类
     * @param columnName        列名
     * @return 属性上的注释信息
     * @throws Exception 如果发生异常
     */
    private String getPropertyComment(PersistentClass persistentClass, String columnName) throws Exception {
        String comment = null;
        Field field = ReflectUtil.getField(persistentClass.getMappedClass(), columnName);
        if (field.isAnnotationPresent(Comment.class)) {
            comment = field.getAnnotation(Comment.class).value();
        } else {
            PropertyDescriptor descriptor = new PropertyDescriptor(field.getName(), persistentClass.getMappedClass());
            Method readMethod = descriptor.getReadMethod();
            Comment columnComment = readMethod.getAnnotation(Comment.class);
            if (columnComment != null) {
                comment = columnComment.value();
            }
        }
        return comment;
    }
}
